package com.netsdk.utils;

import cn.hutool.core.date.DateUtil;
import cn.hutool.core.util.ObjectUtil;
import cn.hutool.core.util.StrUtil;
import com.netsdk.bean.AccessRecord;
import com.netsdk.bean.Result;
import com.netsdk.demo.module.LoginModule;
import com.netsdk.lib.NetSDKLib;
import com.netsdk.lib.ToolKits;
import com.sun.jna.Memory;
import org.springframework.stereotype.Component;

import java.io.UnsupportedEncodingException;
import java.time.LocalDateTime;
import java.util.LinkedList;
import java.util.List;

/**
 * 出入记录工具类
 *
 * @author Yan Xu
 * @version 1.0
 * @date 2021/8/7
 * Copyright © goodits
 */
@Component
public class AccessRecordUtils {
    private static final String charSet = "GBK";

    private static final String convertToStr(byte [] bytes) throws UnsupportedEncodingException {
        return new String(bytes,charSet).trim();
    }

    public Result<List<AccessRecord>> findRecords(String deviceNo, String cardNo, String startTime, String endTime) throws UnsupportedEncodingException {
        boolean login = DeviceUtils.login(deviceNo);
        if (!login) {
            return ResultUtil.error("设备通讯故障");
        }
        NetSDKLib.NET_TIME startNetTime = null;
        if (StrUtil.isNotEmpty(startTime) && !"null".equals(startTime)) {
            LocalDateTime startDateTime = DateUtil.parseLocalDateTime(startTime);
            startNetTime = new NetSDKLib.NET_TIME();
            startNetTime.setTime(startDateTime.getYear(), startDateTime.getMonthValue(), startDateTime.getDayOfMonth(), startDateTime.getHour(), startDateTime.getMinute(), startDateTime.getSecond());

        }
        NetSDKLib.NET_TIME endNetTime = null;
        if (StrUtil.isNotEmpty(endTime) && !"null".equals(endTime)) {
            LocalDateTime endDateTime = DateUtil.parseLocalDateTime(endTime);
            endNetTime = new NetSDKLib.NET_TIME();
            endNetTime.setTime(endDateTime.getYear(), endDateTime.getMonthValue(), endDateTime.getDayOfMonth(), endDateTime.getHour(), endDateTime.getMinute(), endDateTime.getSecond());
        }
        NetSDKLib.NET_RECORDSET_ACCESS_CTL_CARDREC[] records = findRecords(cardNo, startNetTime, endNetTime);
        List<AccessRecord> accessRecordList = new LinkedList<>();
        for (NetSDKLib.NET_RECORDSET_ACCESS_CTL_CARDREC record : records) {
            AccessRecord accessRecord = new AccessRecord();
            accessRecord.setRecordNo(record.nRecNo);
            accessRecord.setCardNo(convertToStr(record.szCardNo));
            accessRecord.setCardName(convertToStr(record.szCardName));
            accessRecord.setUserId(convertToStr(record.szUserID));
            accessRecord.setCardType(record.emCardType);
            accessRecord.setReaderID(convertToStr(record.szReaderID));
            accessRecord.setDoor(record.nDoor);
            accessRecord.setBStatus(record.bStatus);
            accessRecord.setErrorCode(record.nErrorCode);
            accessRecord.setStuTime(record.stuTime.toStringTimeEx());
            accessRecord.setEmMethod(record.emMethod);
            accessRecord.setSnapFtpUrl(convertToStr(record.szSnapFtpUrl));
            accessRecordList.add(accessRecord);
        }
        return ResultUtil.data(accessRecordList);
    }

    /**
     * 查询刷卡记录，获取查询句柄
     *
     * @return
     */
    private static NetSDKLib.NET_RECORDSET_ACCESS_CTL_CARDREC[] findRecords(String cardNo, NetSDKLib.NET_TIME startTime, NetSDKLib.NET_TIME endTime) {
        // 接口入参
        NetSDKLib.FIND_RECORD_ACCESSCTLCARDREC_CONDITION_EX findCondition = new NetSDKLib.FIND_RECORD_ACCESSCTLCARDREC_CONDITION_EX();
        //设置是否支持卡号查询
        findCondition.bCardNoEnable = 0;
        if (StrUtil.isNotBlank(cardNo)) {
            findCondition.bCardNoEnable = 1;
            findCondition.szCardNo = cardNo.getBytes();
        }

        //设置是否支持时间区间查询
        findCondition.bTimeEnable = 0;
        if (ObjectUtil.isNotEmpty(startTime) && ObjectUtil.isNotEmpty(endTime)) {
            findCondition.bTimeEnable = 1;
            findCondition.stStartTime = startTime;
            findCondition.stEndTime = endTime;
        }

        // CLIENT_FindRecord 接口入参
        NetSDKLib.NET_IN_FIND_RECORD_PARAM stIn = new NetSDKLib.NET_IN_FIND_RECORD_PARAM();
        stIn.emType = NetSDKLib.EM_NET_RECORD_TYPE.NET_RECORD_ACCESSCTLCARDREC_EX;
        stIn.pQueryCondition = findCondition.getPointer();

        // CLIENT_FindRecord 接口出参
        NetSDKLib.NET_OUT_FIND_RECORD_PARAM stOut = new NetSDKLib.NET_OUT_FIND_RECORD_PARAM();
        findCondition.write();

        NetSDKLib.NET_RECORDSET_ACCESS_CTL_CARDREC[] pstRecordEx = new NetSDKLib.NET_RECORDSET_ACCESS_CTL_CARDREC[0];
        // 获取查询句柄
        if (LoginModule.netsdk.CLIENT_FindRecord(LoginModule.m_hLoginHandle, stIn, stOut, 5000)) {
            findCondition.read();

            // 用于申请内存，假定2000次刷卡记录
            int nFindCount = 2000;
            NetSDKLib.NET_RECORDSET_ACCESS_CTL_CARDREC[] pstRecord = new NetSDKLib.NET_RECORDSET_ACCESS_CTL_CARDREC[nFindCount];
            for (int i = 0; i < nFindCount; i++) {
                pstRecord[i] = new NetSDKLib.NET_RECORDSET_ACCESS_CTL_CARDREC();
            }

            NetSDKLib.NET_IN_FIND_NEXT_RECORD_PARAM stNextIn = new NetSDKLib.NET_IN_FIND_NEXT_RECORD_PARAM();
            stNextIn.lFindeHandle = stOut.lFindeHandle;
            stNextIn.nFileCount = nFindCount;

            NetSDKLib.NET_OUT_FIND_NEXT_RECORD_PARAM stNextOut = new NetSDKLib.NET_OUT_FIND_NEXT_RECORD_PARAM();
            stNextOut.nMaxRecordNum = nFindCount;
            // 申请内存
            stNextOut.pRecordList = new Memory(pstRecord[0].dwSize * nFindCount);
            stNextOut.pRecordList.clear(pstRecord[0].dwSize * nFindCount);

            // 将数组内存拷贝给指针
            ToolKits.SetStructArrToPointerData(pstRecord, stNextOut.pRecordList);

            if (LoginModule.netsdk.CLIENT_FindNextRecord(stNextIn, stNextOut, 5000)) {
                System.err.println("stNextOut.nRetRecordNum:" + stNextOut.nRetRecordNum);
                if (stNextOut.nRetRecordNum == 0) {
                    return pstRecordEx;
                }
                // 获取卡信息
                ToolKits.GetPointerDataToStructArr(stNextOut.pRecordList, pstRecord);

                // 获取有用的信息
                pstRecordEx = new NetSDKLib.NET_RECORDSET_ACCESS_CTL_CARDREC[stNextOut.nRetRecordNum];
                for (int i = 0; i < stNextOut.nRetRecordNum; i++) {
                    pstRecordEx[i] = new NetSDKLib.NET_RECORDSET_ACCESS_CTL_CARDREC();
                    pstRecordEx[i] = pstRecord[i];
                }
            }
            LoginModule.netsdk.CLIENT_FindRecordClose(stOut.lFindeHandle);
        }
        return pstRecordEx;
    }

}
